package qnit.test.hibiernate.util;

import java.io.UnsupportedEncodingException;
import java.math.BigInteger;
import java.security.Key;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.util.HashMap;
import java.util.Map;

import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.Mac;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.DESKeySpec;
import javax.crypto.spec.SecretKeySpec;

import sun.misc.BASE64Decoder;
import sun.misc.BASE64Encoder;
/**
 * 密码加密工具类
 * 
 * @author yanjr
 *
 */
public class Encrypt  {
	private static final String KEY_MD5 = "MD5";
    private static final String KEY_SHA = "SHA";
    /**
     * MAC算法可选以下多种算法
     * 
     * <pre>
     *  
     * HmacMD5  
     * HmacSHA1  
     * HmacSHA256  
     * HmacSHA384  
     * HmacSHA512 
     * </pre>
*/
    public static final String KEY_MAC = "HmacMD5";
    
    
    
	/**
	 * 加密主方法
	 * 		1：先从properties文件中获取加密方式encrypt_type
	 * 		2：通过encrypt_type 来选择用哪种加密方式
	 * @param str 需要加密的字符串
	 * @param salt 延值
	 * @return 返回加密字符创
	 * @throws Exception 
	 */
	public static String encryptCode(String str, String salt) throws Exception {
		//获取properties文件中的机密方式：encrypt_type
		String encrypt_type = PropUtil.getProperty("encrypt_type");
//		System.out.println("encrypt_type: " + encrypt_type);
		//判断加密方法 
		if(encrypt_type == null && "".equals(encrypt_type)) {
			return null;
		} else if ("MD5".equals(encrypt_type)) {
			return new BigInteger(encryptMD5(str.getBytes())).toString(16);
		} else if ("MD51".equals(encrypt_type)) {
			return encryptMD51(str);
		} else if ("SMD5".equals(encrypt_type)) {
			return encryptSMD5(str, salt);
		} else if("BASE64".equals(encrypt_type)) {
			return encryptBASE64(str.getBytes("UTF-8"));
		} else if("SHA".equals(encrypt_type)) {
			return new BigInteger(encryptSHA(str.getBytes())).toString(16);
		} else if("HMAC".equals(encrypt_type)) {
			return new BigInteger(encryptHMAC(str.getBytes(), initMacKey())).toString(16);
		} else if("DES".equals(encrypt_type)) {
			return new BigInteger(encryptDES(str.getBytes("UTF-8"), initKey())).toString(16);
		}
		return null;
	}
	
	/**
	 * 密码校验方法
	 * @param password	需要校验的密码
	 * @param salt	延值
	 * @param enpass	从数据库得到的密码
	 * @return map
	 * @throws Exception
	 * 
	 * @author bingsx
	 */
	public static Map<String,Object> Compare(String password, String salt, String enpass) throws Exception{
		
		/*
		 * 1.properties获取加密方式
		 * 2.通过获取的加密方式对密码进行加密:这个过程需要判断那种加密方式，步骤同加密方式一样
		 * 3.进行比较
		 * 4.返回map值:一个是是否成功，一个是mes
		 */
		//1
		String encrypt_type = PropUtil.getProperty("encrypt_type");
		//2
		Boolean boo=false;//是否获取在配置文件中获取到加密方式
		String mes=null;//获取方式的提示信息
		String enp=null;//加密后的密码
		if(encrypt_type == null && "".equals(encrypt_type)) {
			boo=false;
			mes="未在配置文件中获取到加密方式";
			enp=null;
		} else if ("MD5".equals(encrypt_type)) {
			enp= new BigInteger(encryptMD5(password.getBytes())).toString(16);
		} else if ("MD51".equals(encrypt_type)) {
			enp= encryptMD51(password);
		} else if ("SMD5".equals(encrypt_type)) {
			enp= encryptSMD5(password, salt);
		} else if("BASE64".equals(encrypt_type)) {
			enp= encryptBASE64(password.getBytes("UTF-8"));
		} else if("SHA".equals(encrypt_type)) {
			enp= new BigInteger(encryptSHA(password.getBytes())).toString(16);
		} else if("HMAC".equals(encrypt_type)) {
			enp= new BigInteger(encryptHMAC(password.getBytes(), initMacKey())).toString(16);
		} else if("DES".equals(encrypt_type)) {
			enp= new BigInteger(encryptDES(password.getBytes("UTF-8"), initKey())).toString(16);
		}
		//3
		if(enp == null && "".equals(enp)){
			boo=false;
			mes="未获得配置文件中的加密方式";
			
		}else if(enp.equals(enpass)){
			boo=true;
			mes="密码匹配成功";
		}else{
			boo=false;
			mes="密码匹配失败";
		}
		//4
		Map<String,Object> map=new HashMap<String, Object>();
		map.put("boo", boo);
		map.put("mes", mes);
		
		
		return map;
	}
	 /**
     * MD5加密
     * 		普通的MD5加密
     * @param data
     * @return
     * @throws Exception
*/
    public static byte[] encryptMD5(byte[] data) throws Exception {

        MessageDigest md5 = MessageDigest.getInstance(KEY_MD5);
        md5.update(data);

        return md5.digest();

    }

	
	/**
	 * MD5加密
	 * 		MD5后，加密字符串进行转换
	 * @param str 要加密的字符串
	 * @return 返回加密后的字符串
	 */
	public static String encryptMD51(String str) {
		MessageDigest messageDigest = null;  
        try {  
            messageDigest = MessageDigest.getInstance(KEY_MD5);  
            messageDigest.reset();  
            messageDigest.update(str.getBytes("UTF-8"));  
        } catch (NoSuchAlgorithmException e) {  
            System.out.println("No Such AlgorithmException caught!");  
            System.exit(-1);  
        } catch (UnsupportedEncodingException e) {  
            e.printStackTrace();  
        }  
        
        byte[] byteArray = messageDigest.digest();  
        StringBuffer md5StrBuff = new StringBuffer();  
  
        for (int i = 0; i < byteArray.length; i++) {              
            if (Integer.toHexString(0xFF & byteArray[i]).length() == 1)  {
            	md5StrBuff.append("0").append(Integer.toHexString(0xFF & byteArray[i]));  
            } else  {
            	md5StrBuff.append(Integer.toHexString(0xFF & byteArray[i]));  
            }
        }  
        return md5StrBuff.toString();
	}
	/**
	 * 	SMD5加密
	 * 		对字符串进行encryptMD51 加密后，在其后缀加上salt延值，
	 * 再惊醒encryptMD51加密
	 * 
	 * @param str 要加密的字符串
	 * @param salt 延值
	 * @return 加密后的字符串
	 */
	public static String encryptSMD5(String str, String salt) {
		return encryptMD51(encryptMD51(str) + salt);
	}
	
	
	/** 
	 * BASE64解密 
	 * @param key 要加密的字段
	 * @return String字符创
	 * @throws Exception 
	 */  
	public static byte[] decryptBASE64(String key) throws Exception {  
	    return (new BASE64Decoder()).decodeBuffer(key);
	}  
	  
	/** 
	 * BASE64加密 
	 * @param key 要加密的字节数组
	 * @return String字符创
	 * @throws Exception 
	 */  
	public static String encryptBASE64(byte[] key) throws Exception {  
	    return (new BASE64Encoder()).encodeBuffer(key);  
	}  
	
	
	 /**
     * SHA加密
     * 
     * @param data
     * @return
     * @throws Exception
*/
    public static byte[] encryptSHA(byte[] data) throws Exception {

        MessageDigest sha = MessageDigest.getInstance(KEY_SHA);
        sha.update(data);

        return sha.digest();

    }

    /**
     * 初始化HMAC密钥
     * 
     * @return
     * @throws Exception
*/
    public static String initMacKey() throws Exception {
        KeyGenerator keyGenerator = KeyGenerator.getInstance(KEY_MAC);
        SecretKey secretKey = keyGenerator.generateKey();
        return encryptBASE64(secretKey.getEncoded());
    }

    /**
     * HMAC 加密
     * 
     * @param data
     * @param key
     * @return
     * @throws Exception
*/
    public static byte[] encryptHMAC(byte[] data, String key) throws Exception {
        SecretKey secretKey = new SecretKeySpec(decryptBASE64(key), KEY_MAC);
        Mac mac = Mac.getInstance(secretKey.getAlgorithm());
        mac.init(secretKey);
        return mac.doFinal(data);
    }

    /**
     * DES 算法 <br>
     * 可替换为以下任意一种算法，同时key值的size相应改变。
     * 
     * <pre>
     * DES                  key size must be equal to 56 
     * DESede(TripleDES)    key size must be equal to 112 or 168 
     * AES                  key size must be equal to 128, 192 or 256,but 192 and 256 bits may not be available 
     * Blowfish             key size must be multiple of 8, and can only range from 32 to 448 (inclusive) 
     * RC2                  key size must be between 40 and 1024 bits 
     * RC4(ARCFOUR)         key size must be between 40 and 1024 bits 
     * </pre>
*/
    public static final String ALGORITHM = "DES";

    /**
     * DES 算法转换密钥<br>
     * 
     * @param key
     * @return
     * @throws Exception
*/
    private static Key toKey(byte[] key) throws Exception {
        SecretKey secretKey = null;
        if (ALGORITHM.equals("DES") || ALGORITHM.equals("DESede")) {
            DESKeySpec dks = new DESKeySpec(key);
            SecretKeyFactory keyFactory = SecretKeyFactory.getInstance(ALGORITHM);
            secretKey = keyFactory.generateSecret(dks);
        } else {
            // 当使用其他对称加密算法时，如AES、Blowfish等算法时，用下述代码替换上述三行代码
            secretKey = new SecretKeySpec(key, ALGORITHM);
        }
        return secretKey;
    }

    /**
     * DES 算法解密
     * 
     * @param data
     * @param key
     * @return
     * @throws Exception
*/
    public static byte[] decrypt(byte[] data, String key) throws Exception {
        Key k = toKey(decryptBASE64(key));
        Cipher cipher = Cipher.getInstance(ALGORITHM);
        cipher.init(Cipher.DECRYPT_MODE, k);
        return cipher.doFinal(data);
    }

    /**
     * DES 算法加密
     * 
     * @param data
     * @param key
     * @return
     * @throws Exception
*/
    public static byte[] encryptDES(byte[] data, String key) throws Exception {
        Key k = toKey(decryptBASE64(key));
        Cipher cipher = Cipher.getInstance(ALGORITHM);
        cipher.init(Cipher.ENCRYPT_MODE, k);
        return cipher.doFinal(data);
    }

    /**
     * DES 算法生成密钥
     * 
     * @return
     * @throws Exception
*/
    public static String initKey() throws Exception {
        return initKey(null);
    }

    /**
     * DES 算法生成密钥
     * 
     * @param seed
     * @return
     * @throws Exception
*/
    public static String initKey(String seed) throws Exception {
        SecureRandom secureRandom = null;
        if (seed != null) {
            secureRandom = new SecureRandom(decryptBASE64(seed));
        } else {
            secureRandom = new SecureRandom();
        }
        KeyGenerator kg = KeyGenerator.getInstance(ALGORITHM);
        kg.init(secureRandom);
        SecretKey secretKey = kg.generateKey();
        return encryptBASE64(secretKey.getEncoded());
    }
    
    
    public static void main(String[] args) {
       /* try {
            String s = "阿伯才的覆盖";
            String b = CryptUtil.encryptBASE64(s.getBytes("UTF-8"));
            System.out.println("BASE64加密后:" + b);
            byte[] c = CryptUtil.decryptBASE64(b);
            System.out.println("BASE64解密后:" + new String(c, "UTF-8"));

            c = encryptMD5(s.getBytes());
            System.out.println("MD5   加密后:" + new BigInteger(c).toString(16));
            System.out.println("MD51   加密后:" + encryptMD51(s));
            System.out.println("SMD5   加密后:" + encryptSMD5(s, "1234"));

            c = encryptSHA(s.getBytes());
            System.out.println("SHA   加密后:" + new BigInteger(c).toString(16));

            String key = initMacKey();
            System.out.println("HMAC密匙:" + key);
            c = encryptHMAC(s.getBytes(), key);
            System.out.println("HMAC  加密后:" + new BigInteger(c).toString(16));

            key = initKey();
            System.out.println(ALGORITHM + "密钥:\t" + key);
            c = encryptDES(s.getBytes("UTF-8"), key);
            System.out.println(ALGORITHM + "   加密后:" + new BigInteger(c).toString(16));
            c = decrypt(c, key);
            System.out.println(ALGORITHM + "   解密后:" + new String(c, "UTF-8"));
        } catch (UnsupportedEncodingException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (Exception e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        */
    	
    	//456cda01994e16ad28a3c11f985b4990
    	
    	
    	
    	Map<String, Object> map = null;
		try {
			map = Compare("阿伯才的覆盖","1234","456cda01994e16ad28a3c11f985b4990");
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
    	
    	
    	System.out.println(map.get("boo"));
    	System.out.println(map.get("mes"));
    	
    	
    	
    	
    	
    	
    	
    }

}
